﻿using System.ComponentModel;
using System.Collections.Specialized;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;

namespace SharpGL.SceneGraph.Primitives.SmartAxies
{
    /// <summary>
    /// The smart axies object.
    /// </summary>
    [TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
    [DataContract(IsReference = true)]
    public class SmartAxies : SceneElement, IRenderable
    {
        #region Private Fields

        private ObservableCollection<Axis> axies = new ObservableCollection<Axis>();
        private ObservableCollection<AxiesWall> walls = new ObservableCollection<AxiesWall>();

        #endregion Private Fields

        #region Private Methods

        private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems != null)
            {
                foreach (var item in e.OldItems)
                {
                    if (item is INotifyPropertyChanged)
                        ((INotifyPropertyChanged)item).PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged);
                }
            }

            if (e.NewItems != null)
            {
                foreach (var item in e.NewItems)
                {
                    if (item is INotifyPropertyChanged)
                        ((INotifyPropertyChanged)item).PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
                }
            }

            if (sender is ObservableCollection<Axies>)
                NotifyPropertyChanged("Axies");
            else if (sender is ObservableCollection<AxiesWall>)
                NotifyPropertyChanged("Walls");
            else
                NotifyPropertyChanged("");
        }

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (sender is Axies)
                NotifyPropertyChanged("Axies[" + sender.GetType() + "]" + "." + e.PropertyName);
            else if (sender is AxiesWall)
                NotifyPropertyChanged("Walls[" + sender.GetType() + "]" + "." + e.PropertyName);
            else
                NotifyPropertyChanged(sender.GetType() + "." + e.PropertyName);
        }

        #endregion Private Methods

        #region Public Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="SmartAxies"/> class.
        /// </summary>
        public SmartAxies()
        {
            Name = "Axies";

            axies.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
            walls.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);

            axies.Add(new Axis(AxisType.Abscissa));
            axies.Add(new Axis(AxisType.Ordinate));
            axies.Add(new Axis(AxisType.Applicate));

            walls.Add(new AxiesWall(AxiesWallType.XOY));
            walls.Add(new AxiesWall(AxiesWallType.XOZ));
            walls.Add(new AxiesWall(AxiesWallType.YOZ));
        }

        #endregion Public Constructors

        #region Public Methods

        /// <summary>
        /// Render to the provided instance of OpenGL.
        /// </summary>
        /// <param name="gl">The OpenGL instance.</param>
        /// <param name="renderMode">The render mode.</param>
        public void Render(OpenGL gl, RenderMode renderMode)
        {
            Rect3D boundingRect = ChildrenBoundingVolume.BoundingRect;
            if (!boundingRect.IsEmpty)
            {
                foreach (AxiesWall wall in walls)
                    wall.Render(gl, boundingRect);

                foreach (Axis axis in axies)
                    axis.Render(gl, boundingRect);
            }
        }

        #endregion Public Methods

        #region Public Properties

        public ObservableCollection<Axis> Axies
        {
            get { return axies; }
        }

        public ObservableCollection<AxiesWall> Walls
        {
            get { return walls; }
        }

        #endregion Public Properties
    }
}
